#include "common.hpp"
#include "yaml-cpp/yaml.h"
#include <filesystem>
#include <fstream>
#include <iostream>
#include <map>

struct Point;

using PointTable_t = std::map<std::string, Point>;

struct Point {
    std::uint16_t addr;
    std::uint16_t len;
    int readFunc;
    int writeFunc;
    double precision;
    std::string unit;
    std::string type;
    std::string defn;
    std::pair<int, int> offset;
    PointTable_t pointTable;
};

#define BYTEWIDTH 8

// #define IS_1P_BREAKER
// #define IS_1PN_BREAKER
#define IS_3PN_BREAKER

const PointTable_t points = {
    // clang-format off
    {"Temp", {0x03, 0x09, 0x03, 0x00, 1.0, "℃", "class", "温度集合",{-1, -1}, {
            {"TempMcu", {0x03, 0x09, 0x03, 0x00, 1.0, "℃", "i16", "片上温度", {0 * BYTEWIDTH, 1 * BYTEWIDTH}, {}}},
            #if defined(IS_1P_BREAKER) || defined(IS_1PN_BREAKER)
            {"TempInA", {0x03, 0x09, 0x03, 0x00, 1.0, "℃", "i16", "进线温度", {2 * BYTEWIDTH, 3 * BYTEWIDTH}, {}}},
            #else
            {"TempInA", {0x03, 0x09, 0x03, 0x00, 1.0, "℃", "i16", "A相进线温度", {2 * BYTEWIDTH, 3 * BYTEWIDTH}, {}}},
            #endif

            #if defined(IS_3PN_BREAKER)
            {"TempInB", {0x03, 0x09, 0x03, 0x00, 1.0, "℃","i16", "B相进线温度", {4 * BYTEWIDTH, 5 * BYTEWIDTH}, {}}},
            {"TempInC", {0x03, 0x09, 0x03, 0x00, 1.0, "℃", "i16", "C相进线温度", {6 * BYTEWIDTH, 7 * BYTEWIDTH}, {}}},
            #endif
            #if defined(IS_1PN_BREAKER) ||  defined(IS_3PN_BREAKER)
            {"TempInN", {0x03, 0x09, 0x03, 0x00, 1.0, "℃","i16", "N相进线温度", {8 * BYTEWIDTH, 9 * BYTEWIDTH}, {}}},
            #endif


            #if defined(IS_1P_BREAKER) || defined(IS_1PN_BREAKER)
            {"TempOutA", {0x03, 0x09, 0x03, 0x00, 1.0, "℃", "i16", "出线温度", {10 * BYTEWIDTH, 11 * BYTEWIDTH}, {}}},
            #else
            {"TempOutA", {0x03, 0x09, 0x03, 0x00, 1.0, "℃", "i16", "A相出线温度", {10 * BYTEWIDTH, 11 * BYTEWIDTH}, {}}},
            #endif
            #if defined(IS_3PN_BREAKER)
            {"TempOutB", {0x03, 0x09, 0x03, 0x00, 1.0, "℃", "i16", "B相出线温度", {12 * BYTEWIDTH, 13 * BYTEWIDTH}, {}}},
            {"TempOutC", {0x03, 0x09, 0x03, 0x00, 1.0, "℃", "i16", "C相出线温度", {14 * BYTEWIDTH, 15 * BYTEWIDTH}, {}}},
            #endif
            #if defined(IS_1PN_BREAKER)||  defined(IS_3PN_BREAKER)
            {"TempOutN", {0x03, 0x09, 0x03, 0x00, 1.0, "℃", "i16", "N相出线温度", {16 * BYTEWIDTH, 17 * BYTEWIDTH}, {}}},
            #endif
    }}},

    {"Unlock", {0x00, 0x01, 0x00, 0x10, 1.0, "", "u16", "解锁", {-1, -1}, {}}},
    {"SwOpen", {0x00, 0x01, 0x00, 0x10, 1.0, "", "u16", "分闸", {-1, -1}, {}}},
    {"SwClose", {0x00, 0x01, 0x00, 0x10, 1.0, "", "u16", "合闸", {-1, -1}, {}}},
    {"Mac", {0x0138, 0x03, 0x03, 0x00, 1.0, "", "str_hex", "mac地址", {-1, -1}, {}}},

    {"DeviceInfo", {0x00, 0x39, 0x11, 0x00, 1.0, "", "class", "设备信息", {-1, -1}, {
            {"prodModel", {0x00, 0x39, 0x11, 0x00, 1.0, "", "str_hex", "产品型号", {0 * BYTEWIDTH, 3 * BYTEWIDTH}, {}}},
            {"DInfo", {0x00, 0x39, 0x11, 0x00, 1.0, "", "u8", "开合闸状态", {4 * BYTEWIDTH, 4 * BYTEWIDTH}, {}}},
            {"sver", {0x00, 0x39, 0x11, 0x00, 1.0, "", "str_hex", "软件版本", {5 * BYTEWIDTH, 6 * BYTEWIDTH}, {}}},
            {"hver", {0x00, 0x39, 0x11, 0x00, 1.0, "", "str_hex", "硬件版本", {7 * BYTEWIDTH, 8 * BYTEWIDTH}, {}}},
            {"sn", {0x00, 0x39, 0x11, 0x00, 1.0, "", "str", "断路器唯一标识", {13 * BYTEWIDTH, 32 * BYTEWIDTH}, {}}},
    }}},

    {"WorkStat", {0x20, 0x01, 0x03, 0x00, 1.0, "", "u16", "工作状态", {-1, -1}, {
            {"swStat", {0x20, 0x01, 0x03, 0x00, 1.0, "", "bits", "分合闸状态,分闸:0, 合闸:1", {7 , 7}, {}}},
            {"model", {0x20, 0x01, 0x03, 0x00, 1.0, "", "bits", "手自动状态,自动:0, 手动:1", {11 , 11}, {}}},
    }}},

    {"error", {0x21, 0x01, 0x03, 0x00, 1.0, "", "u16", "故障", {-1, -1}, {
        {"OverVoltageErr", {0x21, 0x01, 0x03, 0x00, 1.0, "",  "bits", "过压故障", {0 , 0}, {}}},
        {"UnderVoltageErr", {0x21, 0x01, 0x03, 0x00, 1.0,"", "bits", "欠压故障", {1 , 1}, {}}},
        {"LeakageErr", {0x21, 0x01, 0x03, 0x00, 1.0,"", "bits", "漏电故障", {2 , 2}, {}}},
        {"OverLoadErr", {0x21, 0x01, 0x03, 0x00, 1.0,"", "bits", "过载故障", {3 , 3}, {}}},
        {"TempErr", {0x21, 0x01, 0x03, 0x00, 1.0,"", "bits", "温度故障", {5 , 5}, {}}},
        {"LossPhaseErr", {0x21, 0x01, 0x03, 0x00, 1.0, "","bits", "缺相故障", {6 , 6}, {}}},
        {"OverFreqErr", {0x21, 0x01, 0x03, 0x00, 1.0,"", "bits", "过频故障", {7 , 7}, {}}},
        {"UnderFreqErr", {0x21, 0x01, 0x03, 0x00, 1.0, "","bits", "欠频故障", {8 , 8}, {}}},
        {"ButtonTestErr", {0x21, 0x01, 0x03, 0x00, 1.0,"", "bits", "按钮试跳故障", {10 , 10}, {}}},
        {"RemoteTestErr", {0x21, 0x01, 0x03, 0x00, 1.0, "","bits", "远程试跳故障", {11 , 11}, {}}},
        {"PowerLimitErr", {0x21, 0x01, 0x03, 0x00, 1.0, "","bits", "功率限定故障",  {12 , 12}, {}}},
    }}},

    {"warn", {0x22, 0x01, 0x03, 0x00, 1.0,"", "u16", "警告", {-1, -1}, {
        {"OverVoltageWarn", {0x22, 0x01, 0x03, 0x00, 1.0, "","bits", "过压警告", {0 , 0}, {}}},
        {"UnderVoltageWarn", {0x22, 0x01, 0x03, 0x00, 1.0,"", "bits", "欠压警告", {1 , 1}, {}}},
        {"LeakageWarn", {0x22, 0x01, 0x03, 0x00, 1.0, "","bits", "漏电警告", {2 , 2}, {}}},
        {"OverLoadWarn", {0x22, 0x01, 0x03, 0x00, 1.0,"", "bits", "过载警告", {3 , 3}, {}}},
        {"TempWarn", {0x22, 0x01, 0x03, 0x00, 1.0, "","bits", "温度警告", {5 , 5}, {}}},
        {"LossPhaseWarn", {0x22, 0x01, 0x03, 0x00, 1.0, "","bits", "缺相警告", {6 , 6}, {}}},
        {"OverFreqWarn", {0x22, 0x01, 0x03, 0x00, 1.0, "","bits", "过频警告", {7 , 7}, {}}},
        {"UnderFreqWarn", {0x22, 0x01, 0x03, 0x00, 1.0, "","bits", "欠频警告", {8 , 8}, {}}},
        {"PowerLimitWarn", {0x22, 0x01, 0x03, 0x00, 1.0, "","bits", "功率限定警告", {12 , 12}, {}}},
    }}},


#if defined(IS_1PN_BREAKER) || defined(IS_1P_BREAKER)
    {"Ia", {0x40, 0x02, 0x03, 0x00, 0.001, "A", "u32", "电流", {-1, -1}, {}}},
#elif defined(IS_3PN_BREAKER)
    {"current", {0x40, 0x06, 0x03, 0x00, 0.001, "A","class", "电流集合", {-1, -1}, {
        {"Ia", {0x40, 0x06, 0x03, 0x00, 0.001, "A","u32", "A相电流", {0 * BYTEWIDTH, 3 * BYTEWIDTH}, {}}},
        {"Ib", {0x40, 0x06, 0x03, 0x00, 0.001,"A","u32", "B相电流", {4 * BYTEWIDTH, 7 * BYTEWIDTH}, {}}},
        {"Ic", {0x40, 0x06, 0x03, 0x00, 0.001,"A","u32", "C相电流", {8 * BYTEWIDTH, 11 * BYTEWIDTH}, {}}},
    }}},
#endif

#if defined(IS_1PN_BREAKER) || defined(IS_1P_BREAKER)
    {"Ua", {0x48, 0x01, 0x03, 0x00, 0.01,"V","u32", "电压", {-1, -1}, {}}},
#elif defined(IS_3PN_BREAKER)
    {"voltage", {0x48, 0x03, 0x03, 0x00, 0.01,"V", "class", "电压集合", {-1, -1}, {
        {"Ua", {0x48, 0x03, 0x03, 0x00, 0.01,"V","u32", "A相电压", {0 * BYTEWIDTH, 1 * BYTEWIDTH}, {}}},
        {"Ub", {0x48, 0x03, 0x03, 0x00, 0.01,"V","u32", "B相电压", {2 * BYTEWIDTH, 3 * BYTEWIDTH}, {}}},
        {"Uc", {0x48, 0x03, 0x03, 0x00, 0.01,"V","u32", "C相电压", {4 * BYTEWIDTH, 5 * BYTEWIDTH}, {}}},
    }}},
#endif

#if defined(IS_1PN_BREAKER) || defined(IS_1P_BREAKER)
    {"Pa", {0x51, 0x02, 0x03, 0x00, 0.1,"W" ,"u32", "功率", {-1, -1}, {}}},
#elif defined(IS_3PN_BREAKER)
    {"power", {0x51, 0x06, 0x03, 0x00, 0.1,"W" , "class", "功率集合", {-1, -1}, {
        {"Pa", {0x51, 0x06, 0x03, 0x00, 0.1,"W" , "u32", "A相功率", {0 * BYTEWIDTH, 3 * BYTEWIDTH}, {}}},
        {"Pb", {0x51, 0x06, 0x03, 0x00, 0.1, "W" ,"u32", "B相功率", {4 * BYTEWIDTH, 7 * BYTEWIDTH}, {}}},
        {"Uc", {0x51, 0x06, 0x03, 0x00, 0.1, "W" ,"u32", "C相功率", {8 * BYTEWIDTH, 11 * BYTEWIDTH}, {}}},
    }}},
#endif

    // clang-format on

};

void _toYaml(YAML::Node &node, const Point &p)
{
    node["defn"] = p.defn;
    node["addr"] = p.addr;
    node["len"] = p.len;
    node["type"] = p.type;

    if (p.readFunc) {
        node["funCode"].push_back(p.readFunc);
    } else {
        node["funCode"].push_back(YAML::Null);
    }

    if (p.writeFunc) {
        node["funCode"].push_back(p.writeFunc);
    } else {
        node["funCode"].push_back(YAML::Null);
    }

    if (p.precision != 1.0) {
        node["precision"] = p.precision;
    }

    if (p.unit != "") {
        node["unit"] = p.unit;
    }

    if (p.offset.first != -1 && p.offset.second != -1) {
        node["offset"].push_back(p.offset.first);
        node["offset"].push_back(p.offset.second);
    }

    if (!p.pointTable.empty()) {
        for (const auto &[k, v] : p.pointTable) {
            YAML::Node _n {};
            _n["name"] = k;
            _toYaml(_n, v);
            node["subItems"].push_back(_n);
        }
    }
}

void toYaml(const PointTable_t &p, const std::string &fileName)
{
    YAML::Node node {};
    node["encoding"] = "UTF-8";
    node["name"] = "modbus_485_01040300";
    node["model"] = "modbus_485_01040300";

    for (const auto &[key, value] : p) {
        YAML::Node n {};
        n["name"] = key;
        n["defn"] = value.defn;
        n["addr"] = value.addr;
        n["len"] = value.len;
        n["type"] = value.type;

        if (value.readFunc) {
            n["funCode"].push_back(value.readFunc);
        } else {
            n["funCode"].push_back(YAML::Null);
        }

        if (value.writeFunc) {
            n["funCode"].push_back(value.writeFunc);
        } else {
            n["funCode"].push_back(YAML::Null);
        }

        if (value.precision != 1.0) {
            n["precision"] = value.precision;
        }

        if (value.unit != "") {
            n["unit"] = value.unit;
        }

        if (value.offset.first != -1 && value.offset.second != -1) {
            n["offset"].push_back(value.offset.first);
            n["offset"].push_back(value.offset.second);
        }

        if (!value.pointTable.empty()) {
            for (const auto &[k, v] : value.pointTable) {
                YAML::Node _n {};
                _n["name"] = k;
                _toYaml(_n, v);
                n["subItems"].push_back(_n);
            }
        }

        node["resources"].push_back(n);
    }

    std::ofstream fout(fileName);
    fout << node;
    fout.close();
}

int main(int argc, char **argv)
{
    toYaml(points, "./1.yaml");

    return 0;
}
